package com.css.fxfzxczh.modules.fastDisasterAnalysis.fastSeismicInfluence.service.impl;

import com.css.fxfzxczh.base.response.RestResponse;
import com.css.fxfzxczh.constants.YNEnum;
import com.css.fxfzxczh.modules.fastDisasterAnalysis.fastSeismicInfluence.entity.FastSeismicInfluence;
import com.css.fxfzxczh.modules.fastDisasterAnalysis.fastSeismicInfluence.entity.FastSiVersion;
import com.css.fxfzxczh.modules.fastDisasterAnalysis.fastSeismicInfluence.entity.IntensityAttenuation;
import com.css.fxfzxczh.modules.fastDisasterAnalysis.fastSeismicInfluence.service.IntensityAttenuationService;
import com.css.fxfzxczh.modules.fastDisasterAnalysis.fastSeismicInfluence.vo.IntensityAttenuationVO;
import com.css.fxfzxczh.org.entity.DivisionEntity;
import com.css.fxfzxczh.util.*;
import com.css.fxfzxczh.web.PlatformSessionContext;
import com.css.fxfzxczh.zcpt.sys.entity.SUser;
import com.css.fxfzxczh.zcpt.sys.service.SUserService;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.util.GeometricShapeFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: fxfzxzch
 * @Author: zyt
 * @CreateDate: 2023/7/12 11:02
 */
@Service
public class IntensityAttenuationServiceImpl implements IntensityAttenuationService {
    @Resource
    JdbcTemplate jdbcTemplate;
    @Resource
    NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Resource
    SUserService sUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse countEqIntensity(FastSiVersion fastSiVersion, String modelId, IntensityAttenuation modelById) {
        try {
            fastSiVersion.setFvId(UUIDGenerator.getUUID());//主键ID
            int minIntensity = 10;
            int maxIntensity = 6;

            //地震烈度衰减关系模型
            BigDecimal long_ratio1 = modelById.getLongRatio1();
            BigDecimal long_ratio2 = modelById.getLongRatio2();
            BigDecimal long_ratio3 = modelById.getLongRatio3();
            BigDecimal long_ratio4 = modelById.getLongRatio4();
            String long_symbol = modelById.getLongSymbol();
            BigDecimal short_ratio1 = modelById.getShortRatio1();
            BigDecimal short_ratio2 = modelById.getShortRatio2();
            BigDecimal short_ratio3 = modelById.getShortRatio3();
            BigDecimal short_ratio4 = modelById.getShortRatio4();
            String short_symbol = modelById.getShortSymbol();

            BigDecimal formula_ratio1 = modelById.getFormulaRatio1();
            BigDecimal formula_ratio2 = modelById.getFormulaRatio1();
            //长短轴比例
            BigDecimal scale2 = modelById.getScale();

            boolean isNa = false;
            BigDecimal longX = BigDecimal.ZERO;
            BigDecimal shortY = BigDecimal.ZERO;
            BigDecimal M = fastSiVersion.getEarthquakeLevel(); //震级
            FastSeismicInfluence influenceflied = new FastSeismicInfluence();//地震影响场快速生成
            influenceflied.setEarthquakeLevel(M);
            isNa = true;
            //烈度,遍历烈度
            for (int I = 10; I > 5; I--) {
                //罗马数字1-12：1-Ⅰ、2-Ⅱ、3-Ⅲ、4-Ⅳ、5-Ⅴ、6-Ⅵ、7-Ⅶ、8-Ⅷ、9-Ⅸ、10-Ⅹ、11-Ⅺ、12-Ⅻ
                String intensityStr = "";
                if(I==6){
                    intensityStr = "Ⅵ";
                }else if(I==7){
                    intensityStr = "Ⅶ";
                }else if(I==8){
                    intensityStr = "Ⅷ";
                }else if(I==9){
                    intensityStr = "Ⅸ";
                }else if(I==10){
                    intensityStr = "Ⅹ";
                }
                influenceflied.setIntensity(String.valueOf(I));//地震烈度--6
                influenceflied.setIntensitys(intensityStr);//地震烈度--VI
                influenceflied.setIntensity1(intensityStr+"度（"+I+"）度");//地震烈度--VI度(6度)

                //长轴：Ia=4.9024+1.3485M-3.9738Lg(Ra+13)
                //式中，Ia、Ib分别为长、短轴烈度，M为震级，Ra、Rb分别为烈度为I时长、短半轴的长度
                //根据公式计算得到Ra、Rb，如果值为负数，则舍掉，为正的则留下

                BigDecimal Ra = BigDecimal.ZERO;//烈度为Ia时长半轴的长度
                double a = (long_ratio1.add(long_ratio2.multiply(M)).subtract(BigDecimal.valueOf(I)))
                        .divide(long_ratio3, 8, RoundingMode.UP).doubleValue();
                if ("ln".equals(long_symbol)) {
                    Ra = BigDecimal.valueOf(Math.pow(Math.E, a)).subtract(long_ratio4);
                } else if ("lg".equals(long_symbol)) {
                    Ra = BigDecimal.valueOf(Math.pow(10, a)).subtract(long_ratio4);
                }
                if (scale2.compareTo(BigDecimal.ZERO) > 0 && M.compareTo(BigDecimal.valueOf(7)) > -1) {
                    // 当使用破裂尺度公式且震级大于等于7.0级时，使用破裂尺度公式计算出长轴长度，根据长短轴比例计算出短轴长度。
                    influenceflied.setDataSource("2");

                    //M=5.08+1.16*lg(SRL)
                    //M为震级,SRL为破裂尺度
                    //根据公式计算得到SRL
                    BigDecimal SRL = BigDecimal.valueOf(Math.pow(10, formula_ratio1.subtract(M)
                            .divide(formula_ratio2, 8, RoundingMode.UP).doubleValue()));

                    //最终的长轴长度=衰减关系计算的长轴+破裂尺度
                    //最终的长轴长度=Ra*2+SRL
                    //Ra为烈度为Ia时长半轴的长度,SRL为破裂尺度
                    BigDecimal finalRa = Ra.multiply(BigDecimal.valueOf(2)).add(SRL);

                    //最终的短轴长度
                    BigDecimal finalRb = finalRa.divide(scale2, 2, RoundingMode.HALF_UP);

                    if (finalRa.compareTo(BigDecimal.ZERO) < 0) {
                        //finalRa为负数
                        continue;
                    }
                    if (finalRb.compareTo(BigDecimal.ZERO) < 0) {
                        //finalRb为负数
                        continue;
                    }
                    finalRa = finalRa.setScale(1, RoundingMode.HALF_UP);//长轴长度
                    finalRb = finalRb.setScale(1, RoundingMode.HALF_UP);//短轴长度
                    influenceflied.setLongX(finalRa);
                    influenceflied.setShortY(finalRb);
                } else {
                    // 地震影响场可以使用烈度衰减模型进行模拟，当震级小于7.0级时使用椭圆衰减模型，
                    influenceflied.setDataSource("1");

                    // 短轴：Ib=4.3517+ 1.2192M-3.7429Lg(Rb+6)
                    //式中，Ia、Ib分别为长、短轴烈度，M为震级，Ra、Rb分别为烈度为I时长、短半轴的长度
                    //根据公式计算得到Ra、Rb，如果值为负数，则舍掉，为正的则留下

                    BigDecimal Rb = BigDecimal.ZERO;//烈度为Ib时短半轴的长度
                    double b = (short_ratio1.add(short_ratio2.multiply(M)).subtract(BigDecimal.valueOf(I))).divide(short_ratio3, 8, RoundingMode.UP).doubleValue();
                    if ("lg".equals(short_symbol)) {
                        Rb = BigDecimal.valueOf(Math.pow(10, b)).subtract(short_ratio4);
                    } else if ("ln".equals(short_symbol)) {
                        Rb = BigDecimal.valueOf(Math.pow(Math.E, b)).subtract(short_ratio4);
                    }
                    if (Ra.compareTo(BigDecimal.ZERO) < 0) {
                        //Ra为负数
                        continue;
                    }
                    if (Rb.compareTo(BigDecimal.ZERO) < 0) {
                        //Rb为负数
                        continue;
                    }
                    Ra = Ra.multiply(BigDecimal.valueOf(2)).setScale(1, RoundingMode.HALF_UP);//长轴长度
                    Rb = Rb.multiply(BigDecimal.valueOf(2)).setScale(1, RoundingMode.HALF_UP);//短轴长度
                    influenceflied.setLongX(Ra);
                    influenceflied.setShortY(Rb);
                }
                influenceflied.setFsiId(UUIDGenerator.getUUID());//主键ID
                influenceflied.setFvId(fastSiVersion.getFvId());//版本ID（外键）

                String influenceEllipse = null;
                if (!isNa) {
                    //环
                    influenceEllipse = createInfluenceEllipse(fastSiVersion.getLongitude().toString(),
                            fastSiVersion.getLatitude().toString(), influenceflied.getLongX().toString(),
                            influenceflied.getShortY().toString(),
                            String.valueOf(fastSiVersion.getAngle()), longX.toString(), shortY.toString());
                } else {
                    //椭圆
                    influenceEllipse = createInfluenceEllipse(fastSiVersion.getLongitude().toString(),
                            fastSiVersion.getLatitude().toString(), influenceflied.getLongX().toString(),
                            influenceflied.getShortY().toString(),
                            String.valueOf(fastSiVersion.getAngle()), null, null);
                }
                isNa = false;
                longX = influenceflied.getLongX();
                shortY = influenceflied.getShortY();
                influenceflied.setGeom(influenceEllipse);
                influenceflied.setXsemId(fastSiVersion.getXsemId());//事件ID（外键）
                influenceflied.setCreateUser(PlatformSessionUtils.getUserId());
                influenceflied.setCreateTime(PlatformDateUtils.getCurrentTimestamp());
                influenceflied.setDelFlag("0");//0未删除 1已删除
                //计算面积
                double area = getAreaByGeomWKT(influenceEllipse);
                influenceflied.setArea(BigDecimal.valueOf(area));//面积
                //保存地震影响场
                saveFastSeismicInfluence(influenceflied);
                //获取最小地震烈度
                if(minIntensity>I){
                    minIntensity = I;
                }
                //获取最大地震烈度
                if(maxIntensity<I){
                    maxIntensity = I;
                }
            }
            fastSiVersion.setCreateUser(PlatformSessionUtils.getUserId());
            fastSiVersion.setCreateTime(PlatformDateUtils.getCurrentTimestamp());
            fastSiVersion.setDelFlag("0");//0未删除 1已删除
            fastSiVersion.setMinIntensity(BigDecimal.valueOf(minIntensity));//最小地震烈度
            fastSiVersion.setMaxIntensity(BigDecimal.valueOf(maxIntensity));//最大地震烈度
            //当前时间--yyyyMMddHHmmss
            String time = PlatformDateUtils.parseString(new Date(),PlatformDateUtils.DateFormat.YMDHMS_NONE);
            String countStr = "";
            //计算相同时间的版本号数量
            int count = countVersionByTime(time) + 1;
            if(count<10){
                countStr = "00"+count;
            }else if(count<100){
                countStr = "0"+count;
            }else{
                countStr = String.valueOf(count);
            }
            //版本号--yyyyMMddHHmmssYXC数量
            String versionCode = time + "YXC" + countStr;
            fastSiVersion.setVersionCode(versionCode);
            //保存快速生成地震影响场版本信息
            saveFastSiVersion(fastSiVersion);
            return ResponseCreator.createSuccessResponse(fastSiVersion, "生成地震影响场成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RestResponse.fail("生成地震影响场失败！");
    }

    //保存快速生成地震影响场
    @Override
    public int saveFastSeismicInfluence(FastSeismicInfluence entity) {
        //处理空间数据，判断存在自相交则获取修复后的空间数据，否则返回原空间数据wkt
        String geomText = getGeomValidWkt(entity.getGeom());
        entity.setGeom(geomText);

        String sql = "insert into xzch_fast_seismic_influence(fsi_id,xsem_id,area,intensity1,intensitys,intensity," +
                "del_flag,create_user,create_time,fv_id,geom,earthquake_level,long_x,short_y,data_source) " +
                "values (:fsiId,:xsemId,:area,:intensity1,:intensitys,:intensity,:delFlag,:createUser,:createTime,:fvId," +
                "ST_GeometryFromText(:geom,4490),:earthquakeLevel,:longX,:shortY,:dataSource)";
        SqlParameterSource source = new BeanPropertySqlParameterSource(entity);
        //拿到新插入的主键值（i）
        KeyHolder keyHolder = new GeneratedKeyHolder();
        int i = namedParameterJdbcTemplate.update(sql, source, keyHolder);
        return i;
    }

    //保存快速生成地震影响场版本信息
    @Override
    public int saveFastSiVersion(FastSiVersion entity) {
        String sql = "insert into xzch_fast_si_version(fv_id,version_code,angle,image_ids6,image_ids7,image_ids8,image_ids9," +
                "create_user,create_time,del_flag,model_id,xsem_id,image_ids10,longitude,latitude,earthquake_level,min_intensity,max_intensity,select_flag) " +
                "values (:fvId,:versionCode,:angle,:imageIds6,:imageIds7,:imageIds8,:imageIds9,:createUser,:createTime,:delFlag," +
                ":modelId,:xsemId,:imageIds10,:longitude,:latitude,:earthquakeLevel,:minIntensity,:maxIntensity,:selectFlag)";
        SqlParameterSource source = new BeanPropertySqlParameterSource(entity);
        //拿到新插入的主键值（i）
        KeyHolder keyHolder = new GeneratedKeyHolder();
        int i = namedParameterJdbcTemplate.update(sql, source, keyHolder);
        return i;
    }

    //更新快速生成地震影响场版本信息（更新上传图片附件id）
    @Override
    public void updateFastSiVersion(FastSiVersion entity) {
        String sql = "update xzch_fast_si_version set image_ids6 = :imageIds6,image_ids7 = :imageIds7," +
                "image_ids8 = :imageIds8,image_ids9 = :imageIds9,image_ids10 = :imageIds10 " +
                "where fv_id = :fvId";
        SqlParameterSource source = new BeanPropertySqlParameterSource(entity);
        namedParameterJdbcTemplate.update(sql, source);
    }

    //删除快速生成地震影响场版本信息及地震影响场空间数据列表
    @Override
    public void delFastSiVersion(String fvId){
        //删除快速生成地震影响场版本信息
        String sql = "update xzch_fast_si_version set del_flag = ?  where fv_id = ?";
        jdbcTemplate.update(sql, YNEnum.Y.toString(), fvId);
        //删除地震影响场空间数据列表
        String sql1 = "update xzch_fast_seismic_influence set del_flag = ?  where fv_id = ?";
        jdbcTemplate.update(sql1, YNEnum.Y.toString(), fvId);
    }

    //计算相同时间的版本号数量
    public Integer countVersionByTime(String time) {
        String sql = "SELECT count(*) FROM xzch_fast_si_version WHERE version_code like '"+time+"%'";

        return jdbcTemplate.queryForObject(sql, Integer.class);
    }

    //根据事件ID查询地震影响场版本信息列表
    @Override
    public Map<String,Object> getFastSiVersionListByXsemId(String xsemId, int curPage, int pageSize) {
        try {
            String sql = "select * from xzch_fast_si_version where xsem_id=? and del_flag=? " +
                    "order by create_time desc " +
                    "limit " + pageSize + " offset " + (curPage - 1) * pageSize;
            String countSql = "select count(*) from xzch_fast_si_version where xsem_id=? and del_flag=?";
            List<FastSiVersion> fastSiVersionList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(FastSiVersion.class),xsemId, YNEnum.N.toString());
            if(fastSiVersionList!=null && fastSiVersionList.size()>0){
                for(int i=0;i<fastSiVersionList.size();i++){
                    FastSiVersion fastSiVersion = fastSiVersionList.get(i);
                    String userId = fastSiVersion.getCreateUser();
                    String user = sUserService.getSUser(userId);
                    SUser sUser = CreateGson.createGson().fromJson(user, SUser.class);
                    fastSiVersion.setCreateUserName(sUser.getUserName());//生成人
                    fastSiVersionList.set(i,fastSiVersion);
                }
            }
            Integer total = jdbcTemplate.queryForObject(countSql, Integer.class,xsemId, YNEnum.N.toString());

            Map<String, Object> map = new HashMap<String, Object>();
            map.put("total", total);
            map.put("rows", fastSiVersionList);
            return map;
        }catch (EmptyResultDataAccessException e){
            return null;
        }
    }

    //根据版本ID查询地震影响场版本信息
    @Override
    public FastSiVersion getFastSiVersionByFvId(String fvId) {
        String sql = "select * from xzch_fast_si_version where fv_id=? and del_flag=?";
        try {
            FastSiVersion fastSiVersion = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(FastSiVersion.class), fvId, YNEnum.N.toString());
            if(fastSiVersion!=null){
                String userId = fastSiVersion.getCreateUser();
                String user = sUserService.getSUser(userId);
                SUser sUser = CreateGson.createGson().fromJson(user, SUser.class);
                fastSiVersion.setCreateUserName(sUser.getUserName());//生成人
            }

            return fastSiVersion;
        }catch (EmptyResultDataAccessException e){
            return null;
        }
    }

    //根据版本ID查询地震影响场空间数据列表
    @Override
    public List<FastSeismicInfluence> getFastSeismicInfluenceListByFvId(String fvId,String geom) {
        String sql = "select *,st_astext(geom) geom from xzch_fast_seismic_influence where fv_id=? and del_flag=?";
        try {
            if (!PlatformObjectUtils.isEmpty(geom)) {//查询空间范围是否在1个灾区范围烈度内
                sql += " and ST_Within(st_geomfromtext(?,4490),geom)";
                return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(FastSeismicInfluence.class),fvId,YNEnum.N.toString(),geom);
            }else{
                return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(FastSeismicInfluence.class),fvId,YNEnum.N.toString());
            }
        }catch (EmptyResultDataAccessException e){
            return null;
        }
    }

    //调查任务管理--事件的全部快速生成地震影响场版本信息设置未选择
    @Override
    public void unSelectFastSiVersion(String xsemId){
        //调查任务管理是否选择此影响场：0未选择 1已选择
        String sql = "update xzch_fast_si_version set select_flag = ?  where xsem_id = ?";
        jdbcTemplate.update(sql, YNEnum.N.toString(), xsemId);
    }

    //调查任务管理--事件的1个快速生成地震影响场版本信息设置选择
    @Override
    public void setSelectFastSiVersion(String fvId){
        //调查任务管理是否选择此影响场：0未选择 1已选择
        String sql = "update xzch_fast_si_version set select_flag = ?  where fv_id = ?";
        jdbcTemplate.update(sql, YNEnum.Y.toString(), fvId);
    }

    //调查任务管理--根据事件ID删除全部新建的评估子区
    @Override
    public void deleteSurTaskManageType0(String xsemId) {
        //type 0:新建的评估子区   1:重新划定的评估子区
        String sql = "update xczh_survey_task_manage set del_flag= ? where xsem_id = ? and type=?";
        jdbcTemplate.update(sql, YNEnum.Y.toString(), xsemId, YNEnum.N.toString());
    }

    //调查任务管理--查询事件的全部新建的评估子区数量
    @Override
    public int countSurTaskManageByType(String xsemId,String type){
        String sql = "select count(*) from xczh_survey_task_manage where xsem_id = ? and del_flag=?";
        //type 0:新建的评估子区   1:重新划定的评估子区
        if (!PlatformObjectUtils.isEmpty(type)){
            sql += " and type='"+type+"'";
        }
        return jdbcTemplate.queryForObject(sql, Integer.class,xsemId, YNEnum.N.toString());
    }

    //调查任务管理--根据事件ID、影响场ID重新选择快速生成的地震影响场并删除全部新建的评估子区
    @Override
    public void setSelectFastSiVersionByXsemIdFvId(String xsemId,String fvId) {
        //调查任务管理--事件的全部快速生成地震影响场版本信息设置未选择
        unSelectFastSiVersion(xsemId);
        //调查任务管理--事件的1个快速生成地震影响场版本信息设置选择
        setSelectFastSiVersion(fvId);
        //调查任务管理--根据事件ID删除全部新建的评估子区
        deleteSurTaskManageType0(xsemId);
    }

    @Override
    public List<IntensityAttenuationVO> getFastSeiInfAndVerListByFvId(String fvId, String geom) {
        String sql = "select a.*,st_astext(geom) geom,b.angle,b.longitude,b.latitude from xzch_fast_seismic_influence a  " +
                "left join xzch_fast_si_version b on a.fv_id=b.fv_id where a.fv_id=? and a.del_flag=? and b.del_flag=? ";
        try {
            if (!PlatformObjectUtils.isEmpty(geom)) {//查询空间范围是否在1个灾区范围烈度内
                sql += " and ST_Within(st_geomfromtext(?,4490),geom)";
                return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(IntensityAttenuationVO.class),fvId,YNEnum.N.toString(),YNEnum.N.toString(),geom);
            }else{
                return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(IntensityAttenuationVO.class),fvId,YNEnum.N.toString(),YNEnum.N.toString());
            }
        }catch (EmptyResultDataAccessException e){
            return null;
        }
    }

    //调查任务管理--根据事件ID查询选择的地震影响场版本信息
    @Override
    public FastSiVersion getFastSiVersionByXsemId(String xsemId) {
        //调查任务管理是否选择此影响场：0未选择 1已选择
        String sql = "select * from xzch_fast_si_version where xsem_id=? and select_flag=?";
        try {
            FastSiVersion fastSiVersion = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(FastSiVersion.class), xsemId, YNEnum.Y.toString());
            if(fastSiVersion!=null){
                String userId = fastSiVersion.getCreateUser();
                String user = sUserService.getSUser(userId);
                SUser sUser = CreateGson.createGson().fromJson(user, SUser.class);
                fastSiVersion.setCreateUserName(sUser.getUserName());//生成人
            }

            return fastSiVersion;
        }catch (EmptyResultDataAccessException e){
            return null;
        }
    }

    //处理空间数据，判断存在自相交则获取修复后的空间数据，否则返回原空间数据wkt
    @Override
    public String getGeomValidWkt(String geomText) {
        String valid = isGeomValid(geomText);
        if(valid.equals("t")){//正常
            //
        }else if(valid.equals("f")){//自相交
            //修复空间数据自相交，获取修复后的空间数据
            geomText = makeGeomValid(geomText);
        }
        //保持空间数据类型一致性
        if(geomText.indexOf("POLYGON")==0){//面转多面
            geomText = "MULTIPOLYGON(" + geomText.split("POLYGON")[1] + ")";
        }
        return geomText;
    }

    //校验空间数据是否自相交
    @Override
    public String isGeomValid(String geomText) {
        String sql = "SELECT ST_IsValid(geom) FROM st_geomfromtext(?,4490) geom";

        return jdbcTemplate.queryForObject(sql, String.class, geomText);
    }

    //修复空间数据自相交，获取修复后的空间数据
    public String makeGeomValid(String geomText) {
        String sql = "SELECT ST_AsText(ST_MakeValid(geom)) FROM st_geomfromtext(?,4490) geom";

        return jdbcTemplate.queryForObject(sql, String.class, geomText);
    }

    //空间数据经纬度坐标投影转换为米
    private static Geometry lonlat2WebMactor(Geometry geom) {
        Geometry res = null;
        try {
            CoordinateReferenceSystem crsTarget = CRS.decode("EPSG:3857");
            // 投影转换
            MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, crsTarget);
            res = JTS.transform(geom, transform);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    //计算面积
    public static double getAreaByGeomWKT(String geomWKT) {
        double area = 0;
        try {
            GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
            WKTReader reader = new WKTReader(geometryFactory);
            Geometry geom = reader.read(geomWKT);
            geom = lonlat2WebMactor(geom);
            if(geom != null) {
                area = geom.getArea();
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return area;
    }

    //创建地震影响场
    public String createInfluenceEllipse(String lon, String lat, String long_x, String short_y, String angle, String min_long_x, String min_short_y) {
        String result = "";
        try {
            if (!PlatformObjectUtils.isEmpty(lon) && !PlatformObjectUtils.isEmpty(lat)
                    && !PlatformObjectUtils.isEmpty(long_x) && !PlatformObjectUtils.isEmpty(short_y)) {
                double x = Double.parseDouble(lon);//经度
                double y = Double.parseDouble(lat);//纬度
                double macroaxis = Double.parseDouble(long_x) * 1000;//长轴（米）
                double brachyaxis = Double.parseDouble(short_y) * 1000;//短轴（米）
                double direction = 0;//旋转角度
                if (!PlatformObjectUtils.isEmpty(angle)) {
                    direction = Double.parseDouble(angle);//旋转角度
                }
                //创建椭圆
                Polygon ellipse = createEllipse(x, y, macroaxis, brachyaxis, direction);
                if (!PlatformObjectUtils.isEmpty(min_long_x) && !PlatformObjectUtils.isEmpty(min_short_y)) {//内圈椭圆
                    double min_macroaxis = Double.parseDouble(min_long_x) * 1000;//内圈长轴（米）
                    double min_brachyaxis = Double.parseDouble(min_short_y) * 1000;//内圈短轴（米）
                    //创建内圈椭圆
                    Polygon innerEllipse = createEllipse(x, y, min_macroaxis, min_brachyaxis, direction);
                    result = ellipse.toString() + ";" + innerEllipse.toString();
                    result = result.replace("));POLYGON ((", "), (");
                } else {//无内圈椭圆
                    //返回结果
                    result = ellipse.toString();
                }
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }

        return result;
    }

    //椭圆--地震影响场
    /**
     * 定义地球半径（米）
     */
    //private final double R_EARTH = 6371000;
    private final double R_EARTH = 6378137;

    /**
     * 定义地球赤道周长（米）
     */
    private final double P_EARTH = 2 * Math.PI * R_EARTH;

    /**
     * 将Y轴的长度（米）转换成纬度
     *
     * @param length
     * @return
     */
    public double parseYLengthToDegree(double length) {
        //将length长度转换为度数
        double yDegree = length / P_EARTH * 360;
        return yDegree;
    }

    /**
     * 根据所在纬度，将X轴的长度（米）转换成经度
     * （因为不同纬度下，1°经度代表的长度不同）
     *
     * @param y      所在纬度
     * @param length 线段长度
     * @return
     */
    public double parseXLengthToDegree(double y, double length) {
        //将角度（纬度）转换为弧度
        double latRadian = Math.toRadians(y);
        //计算当前纬度地球周长
        double latPEarth = P_EARTH * Math.cos(latRadian);
        //将length长度转换为度数
        double xDegree = length / latPEarth * 360;
        return xDegree;
    }

    /**
     * 根据中心点经纬度、长轴、短轴、角度生成椭圆
     *
     * @param x
     * @param y
     * @param macroaxis
     * @param brachyaxis
     * @param direction
     * @return
     */
    public Polygon createEllipse(double x, double y, double macroaxis, double brachyaxis, double direction) {
        //将长短轴转换为度数
        double macroaxisDegree = parseXLengthToDegree(y, macroaxis);
        double brachyaxisDegree = parseYLengthToDegree(brachyaxis);
        //将夹角转换为弧度
        double radians = Math.toRadians(direction);
        //生成工厂类
        GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
        //设置中心点
        shapeFactory.setCentre(new Coordinate(x, y));
        //设置长轴长度
        shapeFactory.setWidth(macroaxisDegree);
        //设置短轴长度
        shapeFactory.setHeight(brachyaxisDegree);
        //设置长轴和X轴夹角
        shapeFactory.setRotation(radians);
        //生成椭圆对象
        Polygon ellipse = shapeFactory.createEllipse();
        return ellipse;
    }

    @Override
    public String getUnionGeom(String xsemId) {
        String sql = "SELECT st_union ( n.geom ) AS geom FROM xzch_fast_seismic_influence n WHERE n.xsem_id = '"+xsemId+"' and n.del_flag='0'";
        return jdbcTemplate.queryForObject(sql,String.class);
    }

    @Override
    public String getGeom(String fsiId) {
        String sql = "SELECT st_astext ( n.geom ) AS geom FROM xzch_fast_seismic_influence n WHERE n.fsi_id = '"+fsiId+"' and n.del_flag='0'";
        return jdbcTemplate.queryForObject(sql,String.class);
    }
}
